﻿using System.ComponentModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Devonline.Identity.Admin.Controllers;

/// <summary>
/// 资源管理
/// </summary>    
[ApiController]
[Route("api/[controller]")]
[Description("资源管理")]
[Authorize(Roles = GROUP_MAINTAINERS)]
[AccessAuthorize(Code = "AS0XResource", Name = "资源管理", ResourceType = ResourceType.Service, Roles = GROUP_MAINTAINERS)]
public class ResourcesController(
    ILogger<ResourcesController> logger,
    IDataWithAttachmentService<Resource> dataService,
    IExcelExportService excelExportService,
    AuthorizationService authorizationService,
    ResourceAccessStore resourceAccessStore) :
    IdentityDataModelServiceController<Resource, ResourceViewModel>(logger, dataService)
{
    private readonly IExcelExportService _excelExportService = excelExportService;
    private readonly AuthorizationService _authorizationService = authorizationService;
    private readonly ResourceAccessStore _resourceAccessStore = resourceAccessStore;
    private static CancellationToken CancellationToken => CancellationToken.None;

    /// <summary>
    /// 重写基类方法, 在新增时写入 SystemId
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPost, AccessAuthorize(Code = "AS0XResourceICreate"), Description("新增资源")]
    public override async Task<IActionResult> CreateAsync(ResourceViewModel viewModel)
    {
        await SetSystemIdAsync(viewModel);
        return await base.CreateAsync(viewModel);
    }
    /// <summary>
    /// 重写基类方法, 在修改时写入 SystemId
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPut, AccessAuthorize(Code = "AS0XResourceIUpdate"), Description("修改资源")]
    public override async Task<IActionResult> UpdateAsync(ResourceViewModel viewModel)
    {
        await SetSystemIdAsync(viewModel);
        return await base.UpdateAsync(viewModel);
    }

    ///// <summary>
    ///// 导出
    ///// </summary>
    ///// <param name="options"></param>
    ///// <returns></returns>
    //[HttpGet("Export"), AccessAuthorize(Code = "AS0XResourceIExport"), Description("导出资源列表")]
    //public override async Task<IActionResult> ExportAsync(ODataQueryOptions<Resource> options) => await _excelExportService.ExportAsync(await ExportAsync<ResourceExportModel>(options));

    /// <summary>
    /// 修改资源父级
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPost("ChangeParent"), AccessAuthorize(Code = "AS0XResourceIChangeParent"), Description("修改资源父级")]
    public async Task<IActionResult> ChangeParentAsync(ChangeParentViewModel viewModel)
    {
        _logger.LogInformation("user {user} will change the resource {resource} parent to {parent}", _dataService.UserName, viewModel.Id, viewModel.ParentId);
        var resource = await _dataService.GetAsync(viewModel.Id);
        if (resource is null || viewModel.ParentId is null)
        {
            return NotFound();
        }

        try
        {
            await _resourceAccessStore.SetParentAsync(resource, viewModel.ParentId);
            await _dataService.UpdateAsync(resource);
            _logger.LogWarning("user {user} success to change the resource {resource} parent to {parent}", _dataService.UserName, resource.Name, viewModel.ParentId);
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "user {user} change the resource {resource} parent to {parent} throw exception", _dataService.UserName, resource.Name, viewModel.ParentId);
        }

        return BadRequest($"修改资源 {resource.Name} 父级没有成功!");
    }
    /// <summary>
    /// 修改资源所有者
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPost("ChangeOwner"), AccessAuthorize(Code = "AS0XResourceIChangeOwner"), Description("修改资源所有者")]
    public async Task<IActionResult> ChangeOwnerAsync(ChangeOwnerViewModel viewModel)
    {
        _logger.LogInformation("user {user} will change the resource {resource} owner to {owner} and owner type to {ownerType}", _dataService.UserName, viewModel.Id, viewModel.OwnerId, viewModel.IdentityType);
        var resource = await _dataService.GetAsync(viewModel.Id);
        if (resource is null || viewModel.OwnerId is null)
        {
            return NotFound();
        }
        try
        {
            await _resourceAccessStore.SetOwnerAsync(resource, viewModel.OwnerId);
            await _dataService.UpdateAsync(resource);
            _logger.LogWarning("user {user} success to change the resource {resource} owner to {owner} and owner type to {ownerType}", _dataService.UserName, resource.Name, viewModel.OwnerId, viewModel.IdentityType);
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "user {user} change the resource {resource} owner to {owner} and owner type to {ownerType} throw exception", _dataService.UserName, resource.Name, viewModel.OwnerId, viewModel.IdentityType);
        }

        return BadRequest($"修改资源 {resource.Name} 所有者没有成功!");
    }
    /// <summary>
    /// 修改资源可访问级别
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    [HttpPost("ChangeLevel"), AccessAuthorize(Code = "AS0XResourceIChangeLevel"), Description("修改资源可访问级别")]
    public async Task<IActionResult> ChangeLevelAsync(ResourceChangeLevelViewModel viewModel)
    {
        _logger.LogInformation("user {user} will change the resource {resource} level to {level} and access level to {accessLevel}", _dataService.UserName, viewModel.Id, viewModel.LevelName, viewModel.AccessLevel);
        var resource = await _dataService.GetAsync(viewModel.Id);
        if (resource is null || viewModel.LevelName is null)
        {
            return NotFound();
        }
        try
        {
            await _resourceAccessStore.SetLevelAsync(resource, viewModel.LevelName, CancellationToken);
            await _resourceAccessStore.SetAccessLevelAsync(resource, viewModel.AccessLevel, CancellationToken);
            await _dataService.UpdateAsync(resource);
            _logger.LogWarning("user {user} success to change the resource {resource} level to {level} and access level to {accessLevel}", _dataService.UserName, resource.Name, viewModel.LevelName, viewModel.AccessLevel);
            return Ok();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "user {user} change the resource {resource} level to {level} and access level to {accessLevel} throw exception", _dataService.UserName, resource.Name, viewModel.LevelName, viewModel.AccessLevel);
        }

        return BadRequest($"修改资源 {resource.Name} 级别没有成功!");
    }

    /// <summary>
    /// 给当前 resource 设置 SystemId
    /// </summary>
    /// <param name="viewModel"></param>
    /// <returns></returns>
    private async Task SetSystemIdAsync(ResourceViewModel viewModel)
    {
        if (viewModel.ResourceType != ResourceType.System && viewModel.ParentId is not null)
        {
            var parent = await _dataService.GetIfExistAsync(viewModel.ParentId);
            viewModel.SystemId = parent.ResourceType == ResourceType.System ? parent.Id : parent.SystemId;
        }
    }
}